#ifndef C_COMPILER_FOLLOW_H
#define C_COMPILER_FOLLOW_H
#include <Global.h>
#include <iterator>

void Follow() {
    // 初始化所有非终结符的Follow集为空集
    for (const string& vn : VnSet) {
        FollowSet[vn] = unordered_set<string>();
    }
    // 将#加入到文法开始符号program的Follow集中
    FollowSet[start].insert("#");
    bool changed = true;
    while (changed) {
        changed = false;
        // 循环文法集
        for (const auto& [left_vn, right_symbol_list] : production_map) {
            for (const string& rhs : right_symbol_list) {
                istringstream iss(rhs);
                vector<string> symbols((istream_iterator<string>(iss)), istream_iterator<string>());
                for (size_t i = 0; i < symbols.size(); ++i) {
                    const string& B = symbols[i];
                    if (VnSet.count(B)) { // 如果是非终结符
                        unordered_set<string>& followB = FollowSet[B];
                        size_t j = i + 1;
                        while (j < symbols.size()) {
                            const string& beta = symbols[j];
                            if(!VnSet.count(symbols[j])){
                                if(followB.insert(symbols[j]).second){
                                    changed = true;
                                }
                            }
                            const unordered_set<string>& firstOfBeta = FirstSet[beta];
                            bool containsEpsilon = firstOfBeta.count("$");
                            for (const string& terminal : firstOfBeta) {
                                if (terminal != "$") {
                                    if (followB.insert(terminal).second) {
                                        changed = true;
                                    }
                                }
                            }
                            if (containsEpsilon) {
                                ++j;
                            } else {
                                break;
                            }
                        }
                        if (j == symbols.size()) {
                            const unordered_set<string>& followA = FollowSet[left_vn];
                            for (const string& terminal : followA) {
                                if (followB.insert(terminal).second) {
                                    changed = true;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

#endif //C_COMPILER_FOLLOW_H
